//===============================================================================
// Microsoft patterns & practices
// Web Service Software Factory
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Design;
using System.Diagnostics;
using Microsoft.Build.BuildEngine;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.Practices.RecipeFramework.Library;
using System.Globalization;

namespace Microsoft.Practices.VisualStudio.Helper
{
	/// <summary>
	/// Project Node in the current solution
	/// </summary>
	public class ProjectNode: HierarchyNode
	{
		/// <summary>
		/// Visual Studio Project
		/// </summary>
		private IVsProject project;

		protected IVsProject Project
		{
			get { return project; }
		}

		/// <summary>
		/// Builds a project node from the project Guid
		/// </summary>
		/// <param name="vsSolution"></param>
		/// <param name="projectGuid"></param>
		public ProjectNode(IVsSolution vsSolution, Guid projectGuid)
			: base(vsSolution, projectGuid)
		{
			Init();
		}

		private void Init()
		{
			this.project = this.Hierarchy as IVsProject;
			// Commented because it will show up an error dialog before getting back control to the recipe (caller)
			//Debug.Assert(project != null);  
			Debug.Assert(ItemId == VSConstants.VSITEMID_ROOT);
		}

		public bool CanAddItem(string name)
		{
			Guard.ArgumentNotNullOrEmptyString(name, "name");
			return IsValidFullPathName(name);
		}

		/// <summary>
		/// Adds a new item in the project
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public HierarchyNode AddItem(string name)
		{
			Guard.ArgumentNotNullOrEmptyString(name, "name");
			if (!CanAddItem(name))
			{
				throw new InvalidOperationException(
					String.Format(
						CultureInfo.CurrentCulture,
						Properties.Resources.InvalidFileName,
						name));
			}
			FileInfo fileInfo = null;
			if (System.IO.Path.IsPathRooted(name))
			{
				fileInfo = new FileInfo(name);
			}
			else
			{
				fileInfo = new FileInfo(System.IO.Path.Combine(ProjectDir, name));
			}
			if ( fileInfo.Name.Equals(fileInfo.Extension,StringComparison.InvariantCultureIgnoreCase) )
			{
				throw new InvalidOperationException(
					String.Format(
						CultureInfo.CurrentCulture,
						Properties.Resources.CannotCreateItemWithEmptyName));
			}
			if (!File.Exists(fileInfo.FullName))
			{
				File.Create(fileInfo.FullName).Dispose();
			}
			uint itemId = VSConstants.VSITEMID_NIL;
			int found = 1;
			VSDOCUMENTPRIORITY docPri = VSDOCUMENTPRIORITY.DP_Standard;
			int hr = project.IsDocumentInProject(fileInfo.FullName, out found, new VSDOCUMENTPRIORITY[] { docPri }, out itemId);
			Marshal.ThrowExceptionForHR(hr);
			if (found == 0)
			{
				VSADDRESULT result = VSADDRESULT.ADDRESULT_Cancel;
				hr = project.AddItem(VSConstants.VSITEMID_ROOT,
					VSADDITEMOPERATION.VSADDITEMOP_OPENFILE,
					fileInfo.Name, 1, new string[] { fileInfo.FullName },
					IntPtr.Zero, new VSADDRESULT[] { result });
				Marshal.ThrowExceptionForHR(hr);
			}
			hr = project.IsDocumentInProject(fileInfo.FullName, out found, new VSDOCUMENTPRIORITY[] { docPri }, out itemId);
			Marshal.ThrowExceptionForHR(hr);
			if (found == 1)
			{
				return new HierarchyNode(this,itemId);
			}
			return null;
		}

		/// <summary>
		/// Opens an item using the default view
		/// </summary>
		/// <param name="child"></param>
		/// <returns></returns>
		// FXCOP: False positive
		[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public IVsWindowFrame OpenItem(HierarchyNode child)
		{
			Guard.ArgumentNotNull(child, "child");

			Guid logicalView = VSConstants.LOGVIEWID_Primary;
			IntPtr existingDocData = IntPtr.Zero;
			IVsWindowFrame windowFrame;
			int hr = project.OpenItem(child.ItemId, ref logicalView, existingDocData, out windowFrame);
			Marshal.ThrowExceptionForHR(hr);
			return windowFrame;
		}

		/// <summary>
		/// Gets the MSBuild project
		/// </summary>
		public Project MSBuildProject
		{
			get
			{
				return Engine.GlobalEngine.GetLoadedProject(Path);
			}
		}

		/// <summary>
		/// Gets the msbuild item
		/// </summary>
		/// <param name="includeSpec"></param>
		/// <returns></returns>
		public BuildItem GetBuildItem(string includeSpec)
		{
			Project msbuildProject = MSBuildProject;
			foreach (BuildItemGroup group in msbuildProject.ItemGroups)
			{
				foreach (BuildItem buildItem in group)
				{
					if (buildItem.Include == includeSpec)
					{
						return buildItem;
					}
				}
			}
			return null;
		}

		public string ProjrefOfProject
		{
			get
			{
				string result = string.Empty;
				int hr = Solution.GetProjrefOfProject(Hierarchy, out result);
				Marshal.ThrowExceptionForHR(hr);
				return result;
			}
		}

		public VSLangProj.VSProject VSProject
		{
			get
			{
				if (ExtObject is EnvDTE.Project)
				{
					EnvDTE.Project extObject = (EnvDTE.Project)ExtObject;
					if (extObject.Object is VSLangProj.VSProject)
					{
						return (VSLangProj.VSProject)extObject.Object;
					}
				}
				return null;
			}
		}

		public void AddAssemblyReference(string assemblyPath)
		{
			if (VSProject != null)
			{
				VSLangProj.References references = VSProject.References;
				if (references != null )
				{
					references.Add(assemblyPath);
				}
			}
		}

		/// <summary>
		/// Adds the project reference.
		/// </summary>
		/// <param name="projectId">The project id.</param>
		public void AddProjectReference(Guid projectId)
		{
			if (ProjectGuid == projectId)
			{
				return;
			}
			ProjectNode referencedProject = new ProjectNode(Solution,projectId);
			if ( VSProject!=null )
			{
				VSLangProj.References references = VSProject.References;
				if (references != null && referencedProject.ExtObject is EnvDTE.Project)
				{
					references.AddProject(referencedProject.ExtObject as EnvDTE.Project);
				}
			}
		}
	}
}
